package gui;

import Protocol.NewQueryAlertPacket;
import Protocol.PacketFactory;
import Protocol.PacketTypeKeeper;
import Protocol.QueryRequestPacket;
import Protocol.QueryResponsePacket;
import config.Config;
import config.Content;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.MatteBorder;

/**
 * JPanel for the MasterClient to manage queries.
 * @author Joep Kemperman
 */
public class QueryPanel extends JPanel implements ActionListener{
	private JPanel queryContainer; // Contains containers containing queries. Old name: queryContainerContainer
	private ArrayList<JPanel> queryContent; // Contains one query
	private ArrayList<DeleteButton> deleteButtons;
	private ArrayList<JTextField> names;
	private ArrayList<JTextArea> queries;
	private ArrayList<Integer> deletedQueries;
	private JPanel buttonContainer;
	private JButton save, refresh, add;
	
	
	private static final String QUERY = "SELECT [query_id], [query_name], [query_string] FROM [BunieQuery];";
			
	/**
	 * Constructor: Sets all attributes.
	 */
	public QueryPanel() {
		super();
		setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
		queryContainer = new JPanel();
		queryContainer.setLayout(new BoxLayout(queryContainer, BoxLayout.PAGE_AXIS));
		queryContent = new ArrayList<JPanel>();
		buttonContainer = new JPanel();
		deleteButtons = new ArrayList<DeleteButton>();
		names = new ArrayList<JTextField>();
		queries = new ArrayList<JTextArea>();
		deletedQueries = new ArrayList<Integer>();
		save = new JButton("Save");
		refresh = new JButton("Refresh");
		add = new JButton("Add");
		init();
	}
	
	/**
	 * Adds all attributes and action listeners.
	 */
	private void init() {
		setQueries();
		add(queryContainer);
		add.addActionListener(this);
		buttonContainer.add(add);
		save.addActionListener(this);
		buttonContainer.add(save);
		refresh.addActionListener(this);
		buttonContainer.add(refresh);
		add(buttonContainer);
	}

	/**
	 * Requests all queries.
	 * @return Database result with required queries.
	 */
	private ArrayList<String[]> getQueries() {
		ArrayList<String[]> result = new ArrayList<String[]>();
		QueryRequestPacket request = 
				(QueryRequestPacket) PacketFactory.getPacket(PacketTypeKeeper.QUERYREQUESTPACKET);
		request.setQuery(QUERY);
        request.setStatus(QueryRequestPacket.SELECT);
        request.setQueryName("Queries for knopjes");
		QueryResponsePacket response = null;
		try {
			response = (QueryResponsePacket) Content.connection.communicate(request);
		} catch (Exception ex) {
			Content.log.println("Failed to get Queries from database (QueryPanel).");
		}
		result = response.getListWithAccounts();
		return result;
	}
	
	/**
	 * Adds up-to-date queries and their names.
	 * to be add6ed to the panel.
	 */
	private void setQueries() {
		ArrayList<String[]> result = getQueries();
		int arrayId = 0;
		for (String[] row : result) {
			// DeleteButton
			DeleteButton db = new DeleteButton("Delete", arrayId, Integer.parseInt(row[0]));
			db.setAlignmentY(TOP_ALIGNMENT);
			db.addActionListener(this);
			deleteButtons.add(db);
			
			// Name
			JTextField jtf = new JTextField(row[1], 20);
			jtf.setAlignmentY(TOP_ALIGNMENT);
			names.add(jtf); // Query name
			
			// Query
			JTextArea jta = new JTextArea(row[2], 3, 20);
			jta.setAlignmentY(TOP_ALIGNMENT);
			jta.setLineWrap(true);
			jta.setWrapStyleWord(true);
			queries.add(jta);
			
			arrayId++;
		}
		addQueries();
	}
	
	/**
	 * Adds all attributes related to queries to the JPanel.
	 * Also does Layout stuff
	 * @author Joep Kemperman, Kay van Bree
	 */
	private void addQueries() {		
		for (int i=0; i<names.size() ; i++) {
			// The queryContent panel
			JPanel panel = new JPanel();
			JPanel topPanel = new JPanel();
			topPanel.setLayout(new FlowLayout());
			
			// Add a bottom border
			panel.setBorder(new MatteBorder(0, 0, 1, 0, Color.BLACK));
			
			// Set the layout
			BorderLayout layout = new BorderLayout();
			panel.setLayout(layout);
			
			// Add the fields
			topPanel.add(names.get(i));
			topPanel.add(deleteButtons.get(i));
			panel.add(topPanel, BorderLayout.NORTH);
			
			panel.add(queries.get(i), BorderLayout.CENTER);
			
			queryContainer.add(panel);
			queryContent.add(panel);
		}
	}
	
	/**
	 * Saves queries
	 * @author Joep Kemperman, Patrick Wobben
	 */
	private void save() {
		boolean failed = false;
		String query;
                String queryName;
		
                try {
                
			for (int i=0; i<names.size(); i++) {
                            QueryRequestPacket request = 
				(QueryRequestPacket) PacketFactory.getPacket(PacketTypeKeeper.QUERYREQUESTPACKET);
                            query = queries.get(i).getText();
                            queryName = names.get(i).getText();
                           
				if (isValidQuery(query)) {
					request.setQuery(query);
					request.setQueryName(queryName);
					request.setQueryId(deleteButtons.get(i).getQueryId());
					request.setStatus(QueryRequestPacket.UPDATE);
					try {
						Content.connection.communicate(request);
					} catch (Exception ex) {
						Content.log.println("Couldn't save query");							
					}
				} else
				throw new Exception(queryName);
			}
		} catch (Exception e) {
			invalidQueryMessage(e.getMessage());
			failed = true;
		}
		if (failed == false)
		for (int queryId : deletedQueries) {
			QueryRequestPacket request = 
				(QueryRequestPacket) PacketFactory.getPacket(PacketTypeKeeper.QUERYREQUESTPACKET);
            request.setQuery("DELETE FROM [dbo].[BunieQuery] WHERE [query_id] = " + queryId + ";");
            request.setStatus(QueryRequestPacket.DELETE);
			try {
				Content.connection.communicate(request);
			} catch (Exception ex) {
				Content.log.println("Couldn't delete query");							
			}
		}
		resetQueryStatus();
	}
	
	/**
	 * Checks if a query is valid or not
	 * @param query Query to be validated.
	 * @return True if query is valid; false if query is invalid.
	 */
	private boolean isValidQuery(String query) {
		QueryRequestPacket request = 
				(QueryRequestPacket) PacketFactory.getPacket(PacketTypeKeeper.QUERYREQUESTPACKET);
		QueryResponsePacket response = null;
		request.setQuery(query);
        request.setStatus(QueryRequestPacket.SELECT);
		try {
			response = (QueryResponsePacket) Content.connection.communicate(request);
		} catch (Exception ex) {
			Content.log.println("Failed to validate query (QueryPanel).");
		}
		if (response.queryResult == 1)
			return true;
		else
			return false;
		
	}
	
	/**
	 * Discards all changes and reloads queries.
	 */
	private void refresh() {
		queryContainer.removeAll();
		deleteButtons.clear();
		names.clear();
		queries.clear();
		deletedQueries.clear();
		setQueries();
		invalidate();
		validate();
	}
	
	/**
	 * Deletes components related to given query and
	 * adds the query id to an ArrayList to be deleted later on.
	 * @param id Query id
	 */
	private void delete(int id) {
		queryContainer.remove(id);
		queryContent.remove(id);
		deleteButtons.remove(id);
		names.remove(id);
		queries.remove(id);
		
		for (int i=id; i<deleteButtons.size(); i++) {
			deleteButtons.get(i).decrement();
		}
		queryContainer.invalidate();
		queryContainer.validate();
		invalidate();
		validate();
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() instanceof DeleteButton) {
			DeleteButton db = (DeleteButton) e.getSource();
			delete(db.getArrayId());
			deletedQueries.add(db.getQueryId());
		} else if (e.getSource() == save) 
			save();
		else if (e.getSource() == refresh)
			refresh();
		else if (e.getSource() == add)
			addQuery();
	}

	/**
	 * Shows a message dialog which tells which query is invalid.
	 * @param queryName Name of the invalid query.
	 */
	private void invalidQueryMessage(String queryName) {
		JOptionPane.showMessageDialog(this,
		"Could not save queries:\n\"" + queryName + "\" has an invalid query.",
		"Warning",
		JOptionPane.WARNING_MESSAGE);
	}

	/**
	 * Adds room for a new management query.
	 */
	private void addQuery() {
		NewQueryDialog  newQuery = new NewQueryDialog();
		/*
		// Add a new basic query.
		QueryRequestPacket request = 
				(QueryRequestPacket) PacketFactory.getPacket(PacketTypeKeeper.QUERYREQUESTPACKET);
		String queryName = Long.toString(System.currentTimeMillis());
		String query = "SELECT 13 AS \'Columnname\', 37 AS \'Columname2\';";
		request.setQueryName(queryName);
		request.setQuery(query);
		request.setStatus(QueryRequestPacket.INSERT);
		try {
			Content.connection.communicate(request);
		
			// Get all queryinformation from added query. Required to get the database id.
			request = 
					(QueryRequestPacket) PacketFactory.getPacket(PacketTypeKeeper.QUERYREQUESTPACKET);
			request.setQuery("SELECT [query_id] FROM [BunieQuery] WHERE [query_name] = " + queryName);
			request.setStatus(QueryRequestPacket.SELECT);
			QueryResponsePacket response = null;
			try {
				response = (QueryResponsePacket) Content.connection.communicate(request);
				ArrayList<String[]> addedQuery = response.getListWithAccounts();
				int queryId = Integer.parseInt(addedQuery.get(0)[0]);
				int arrayId = names.size() + 1;
				
				JPanel panel = new JPanel();
				
				// Add delete button
				DeleteButton db = new DeleteButton("Delete", arrayId, queryId);
				db.setAlignmentY(TOP_ALIGNMENT);
				db.addActionListener(this);
				deleteButtons.add(db);
				panel.add(db);

				// Name
				JTextField jtf = new JTextField(queryName, 20);
				jtf.setAlignmentY(TOP_ALIGNMENT);
				names.add(jtf); // Query name
				panel.add(jtf);
				
				// Query
				JTextArea jta = new JTextArea(query, 3, 20);
				jta.setAlignmentY(TOP_ALIGNMENT);
				jta.setLineWrap(true);
				jta.setWrapStyleWord(true);
				queries.add(jta);
				panel.add(jta);
			} catch (Exception ex) {
				Content.log.println("Couldn't add a new query (couldn't receive)");
			}
		} catch (Exception ex) {
			Content.log.println("Couldn't add a new query");
		}		*/
	}
	
	/**
	 * Creates and sets a new query status.
	 */
	private void resetQueryStatus() {
		Random random = new Random();
		String seed = Long.toString(Math.abs(random.nextLong()), 36);
		//Config.queryStatus = seed;
		QueryRequestPacket request = 
				(QueryRequestPacket) PacketFactory.getPacket(PacketTypeKeeper.QUERYREQUESTPACKET);
		request.setSeed(seed);
		request.setStatus(QueryRequestPacket.RESEED);
		try {
			Content.connection.send(request);
		} catch (Exception ex) {
			Content.log.println("Couldn't reseed");
		}
	}
	
	/**
	 * JButton with arrayId associated with a query in QueryPanel
	 * @author Joep Kemperman
	 */
	private class DeleteButton extends JButton {
		private int arrayId;
		private int queryId;
		
		public DeleteButton(String name, int arrayId, int queryId) {
			super(name);
			this.arrayId = arrayId;
			this.queryId = queryId;
		}
		
		/**
		 * Decrements the arrayId.
		 * Neccesary if a previous query was deleted.
		 */
		public void decrement() {
			arrayId--;
		}
		
		/**
		 * Getter for arrayId.
		 * @return Id of the button.
		 */
		public int getArrayId() {
			return arrayId;
		}
		
		/**
		 * Getter for queryId.
		 * @return Id of the query.
		 */
		public int getQueryId() {
			return queryId;
		}
	}
}
